#include "Program.h"
#include "stdafx.h"

using namespace std;

Program::Program()
{
	m_validWorkingDirectory = false;
	//Has inputname of the file	
	m_inputName = _T("");
	//Has the output name
	m_outputName = _T("");	
}

//Arguments are:
//-i: input filename
//-o: output filename
//-c: What converter to run
//-md:  model directory path, the path to models folder
//	[ rel ] as optional keyword to -wd  that tells the new path is relative. Keyword comes after the path  example:   -wd ../../ rel
//			It's relative from this files path
const int Program::Run(const int a_argc, _TCHAR* a_argv[] )
{		
	//Has the working directory path
	_TCHAR* f_workingDirectory = new _TCHAR[MAX_PATH];	
	
	const _TCHAR* f_processFile = (a_argc >= 1) ? a_argv[0] : _T("NO FILE");	
	bool f_canContinue = true;

	#if defined(_TESTING)
		Cout << __T("TEST MODE") << endl;
	#endif
	
	//Reads from the argv array
	ReadArguments(a_argc, a_argv, f_processFile, f_workingDirectory);

	//Checks if m_validWorkingDirectory is true, if false it tries to set the working directory to this process/exe file 
	if ( !TryToChangeWorkingDirectory( f_processFile, f_workingDirectory) )
	{
		#if defined (_DEBUG)
			Cout << _T("Failed to wd to process directory") << endl;
		#endif
		f_canContinue = false;
	}
	else
	{
		//Clear the converterlog if working directory is ok!
		ClearLog();
	}
	//if testing there's no need to supply the filename, it will automatically fill in the "test" file
	#if defined(_TESTING)
		if (_tcscmp(m_inputName, _T("") ) == 0)
		{
			m_inputName = _T("playertest_walk.fbx");
			//m_inputName = _T("Gorbatras_ConverterTest.fbx");
			Cout << _T("TEST: inputname added") << endl;
		}
		if (_tcscmp(m_outputName, _T("") ) == 0)
		{
			m_outputName = _T("Gorbatras_ConverterTest.json");
			Cout << _T("TEST: outputname added") << endl;
		}
	#endif
	
	//2. Checks that input & output exists	
	if (_tcscmp(m_inputName, _T("") ) == 0 || _tcscmp(m_outputName , _T("")) == 0 )
	{		
		#if defined (_DEBUG)
			Cout << _T("Need input or output filename") << endl;		
		#endif
			
		LogMessage(L"Bad input or output filename");		
		f_canContinue = false;
	}
	//Bai workingDirectory!
	delete[] f_workingDirectory;
	
	//OK, Now that input & output & working directory is correct we can continue with the converter!
	if (f_canContinue)
	{		
		//Start Converter
		LogMessage(L"Started Converter");
		#if defined (_DEBUG)
			Cout << _T("Started Converter") << endl;
		#endif			
		
		int f_status = Status::Converter_Failed;
		try
		{			
			std::unique_ptr<GC::ConverterApp> f_converter( new GC::ConverterApp(m_inputName, m_outputName, GC::ConverterApp::ConverterType::Fbx ));			
			boost::function<void(const wchar_t*, const bool)> f_logFunction = boost::bind<void>(&Program::LogMessage, this, _1, _2);
			f_status = f_converter->RunConverter( f_logFunction  );	
			f_converter.release();
			//delete f_converter;
			LogMessage(L"Finished Converting");
			#if defined (_DEBUG)
				Cout << _T("Finished Converter") << endl;
			#endif	

		}
		catch (std::exception &e)
		{
			LogMessage(L"Converter crashed unexpectedly");
			#if defined (_DEBUG)
				Cout << _T("Converter Crashed") << endl;
			#endif	
		}			

		//returns 0
		return f_status;
		//return Status::Success;
	}
	else
	{		
		//Return 1 to tell program failed
		LogMessage(L"Failed to initilize converter");
		return Status::Program_Failed;
	}
}

void Program::ReadArguments(const int a_argc, _TCHAR* a_argv[], const _TCHAR* a_processFile, _TCHAR* a_workingDirectory )
{
	for (int i = 1; i < a_argc; i++)
	{
		const _TCHAR* f_argument = a_argv[i];

		//Inputfile name
		if (_tcscmp( f_argument,  _T( "-i" )) == 0 && i+1 < a_argc )
		{
			m_inputName = a_argv[i+1];
		}
		//Output path & filename
		else if (_tcscmp( f_argument, _T( "-o" )) == 0 && i+1 < a_argc )
		{
			m_outputName = a_argv[i+1];
		}
		//What converter to use if there's any doubt
		else if (_tcscmp( f_argument ,_T( "-c" ))== 0 && i+1 < a_argc)
		{

		}
		//The path to the "new" working directory
		else if (_tcscmp( f_argument, _T( "-wd" )) == 0 && i+1 < a_argc )
		{
			//Check for rel the additional keyword
			if (i+2 < a_argc && _tcscmp(a_argv[i+2], _T("-rel")) == 0)
			{
				//Path is now at THIS process/exe file
				GetProcessDirectory( a_processFile, a_workingDirectory, MAX_PATH );
				//Add processpath + the relative path
				_tcscat_s(a_workingDirectory, MAX_PATH, a_argv[i+1] );				
			}
			else
			{
				//Copy the path to f_workingDirectory
				_tcscpy_s(a_workingDirectory, MAX_PATH , a_argv[i+1] );
			}	
			
			//Try to change the working directory
			if ( _tchdir( a_workingDirectory ) == 0)
			{	
				//If it managed to change directory it's a valid directory
				m_validWorkingDirectory = true;				
			}
			//Debug message!
			#if defined (_DEBUG)
			else
			{
				Cout << _T("Failed to change wd to users choice") << endl;
			}			
			#endif
		}				
	}
}

//Returns true if the working directory is ok or if it 
const bool Program::TryToChangeWorkingDirectory( const _TCHAR* a_processArgument, _TCHAR* a_workingDirectoryStr )
{
	//Check if the current directory isn't valid
	if (!m_validWorkingDirectory )
	{
		//If a_processArgument never was set
		if ( _tcscmp( a_processArgument, _T("NO FILE") ) == 0 )
		{
			return false;
		}

		_TCHAR pwd[MAX_PATH];
		//Get current working directory
		GetCurrentDirectory(MAX_PATH, pwd);			
		
		//Write processDirectory to a_workingDirectoryStr
		GetProcessDirectory(a_processArgument, a_workingDirectoryStr, MAX_PATH);	

		//Compare if current working directory is equal to process directory 
		if (_tcscmp(pwd, a_workingDirectoryStr ) == 0 )
		{		
			m_validWorkingDirectory = true;			
		}
		//If they are not equal then change the working directory
		else
		{
			//Attempt to change and check if it succeeds
			if ( _tchdir( a_workingDirectoryStr ) == 0)
			{	
				m_validWorkingDirectory = true;				
			}
			//Failed to change, return false!
			else
			{
				return false;	
			}
		}	
	}

	return true;
}
//Clears the converterlog file
void Program::ClearLog()
{
	//If the working directory is not valid you can't log to file so.. exit from log file!
	if (!m_validWorkingDirectory)
	{
		return;
	}

	try
	{
		const _TCHAR* f_logfileName = _T("converterlog.txt");
		wofstream f_logFile;		
		f_logFile.open( f_logfileName, ios::trunc );
		f_logFile.close();
	}	
	catch (std::exception &e)
	{
			
	}
}

void Program::LogMessage( const wchar_t* a_msg, const bool a_newline)
{
	//If the working directory is not valid you can't log to file so.. exit from log file!
	if (!m_validWorkingDirectory)
	{
		return;
	}

	try
	{
		const _TCHAR* f_logfileName = _T("converterlog.txt");
		wofstream f_logFile;
		
		//if (a_append) { f_logFile.open( f_logfileName, ios::app); } 
		//else { f_logFile.open( f_logfileName ); }
		f_logFile.open( f_logfileName, ios::app );

		if (f_logFile.is_open() )
		{
			f_logFile << a_msg;
			if (a_newline) f_logFile << endl;
		}

		f_logFile.close();
	}
	catch (std::exception &e)
	{

	}	
}

//Copies the process directory path to a_workingDirectoryStr
void Program::GetProcessDirectory(const _TCHAR* a_processArgument, _TCHAR* a_workingDirectoryStr,const int a_strLength )
{
	tpath f_directoryName;	
	if (_UNICODE)
	{
		tpath w(a_processArgument );
		f_directoryName = w.parent_path();
		
		 _tcscpy_s(a_workingDirectoryStr,  a_strLength ,  const_cast<wchar_t*>( f_directoryName.wstring().c_str()) );		
	}
	else
	{
		tpath p(a_processArgument );
		f_directoryName = p.parent_path();		
		_tcscpy_s(a_workingDirectoryStr,  a_strLength, (_TCHAR*)f_directoryName.string().c_str() );	
	}
}